package top.wuxiaohan.operatingSystemCourse.kernel;

import top.wuxiaohan.operatingSystemCourse.Global;
import top.wuxiaohan.operatingSystemCourse.myRunnable.InitRunnable;
import top.wuxiaohan.operatingSystemCourse.myRunnable.MyRunnable;
import top.wuxiaohan.operatingSystemCourse.shell.Shell;

/**
 * 模拟操作系统内核
 */
public class Kernel {

    /**
     * 持有单例对象
     */
    private static Kernel kernel;

    /**
     * 时间片计数
     */
    private int clockInterruptNo;

    /**
     * 就绪队列和阻塞队列
     */
    private ReadyList readyList;
    private BlockList blockList;

    /**
     * 进程计数器，存储当前的进程数
     */
    private volatile int processNum;


    /**
     * 当前运行的进程PCB
     */
    private PCB runningProcess;

    /**
     * 时钟中断线程循环检测值
     */
    private volatile boolean clock = true;

    /**
     * 私有构造函数
     */
    private Kernel() {
    }

    /**
     * 初始化内核，并建立一个shell进程
     */
    public Shell init() {

        //时钟中断计数从0开始
        clockInterruptNo = 0;

        //进程计数器归0
        processNum = 0;

        //初始化就绪队列和阻塞队列
        readyList = new ReadyList();
        blockList = new BlockList();

        //模拟时钟中断开始运行
        clockThread.start();

        //建立init进程
        TreeNode treeNode = new TreeNode(null);

        //建立init进程的PCB
        PCB initPCB = new PCB(0,"init",null, Type.RUN, treeNode,0,InitRunnable.getInitRunnable());

        //TODO initPCB尚未完工

        //返回一个shell对象，在新的Java线程中与内核进行交互（否则会阻塞内核）
        return new Shell(this);
    }

    /**
     * 单例的获取
     */
    public static Kernel getKernel() {
        if (kernel == null)
            return new Kernel();
        else
            return kernel;
    }

    /**
     * 模拟时钟中断
     */
    private Thread clockThread = new Thread(() -> {

        while (clock) {
            try {
                timeOut();
                Thread.sleep(Global.TIME_SLICE);
                //这里只是模拟了剥夺过程，并不是真正的剥夺，
                //模拟调度的进程所要做的仅仅是打印进程名
            } catch (InterruptedException e) {
                clock = false;
                e.printStackTrace();
            }
        }
        //System.out.println("模拟始终中断结束");
    });

    /**
     * 供外部调用取消或开启时钟中断
     */
    public void setClock(boolean clock) {

        this.clock = clock;
        if (this.clock)
            clockThread.start();
    }


    /* ************************************* 分割线 *************************************** */


    /**
     * 创建进程API
     *
     * @param pidName    进程名
     * @param priority   进程优先级
     * @param parentPID  父进程PID
     * @param resources  资源控制块
     * @param myRunnable 执行代码接口
     * @return 状态码
     */
    public synchronized StatusCode create(
            String pidName,
            int priority,
            int parentPID,
            RCB resources,
            MyRunnable myRunnable) {

        //避免超过最大进程数
        if (processNum < 0 && processNum > Global.MAX_PROCESS_NUM) {
            return StatusCode.MORE_THAN_MAX_PROCESS_NUMBER;
        }

        //通过进程号找到父进程
        TreeNode parentProcessTreeNode = findParentProcessTreeNode(parentPID);
        //建立子进程的进程树节点
        TreeNode childProcessTreeNode = new TreeNode();
        //设置子进程的父进程指针
        childProcessTreeNode.setParentProcess(parentProcessTreeNode);
        //将子进程挂到父进程下
        parentProcessTreeNode.setChildProcess(childProcessTreeNode);

        //新建PCB
        PCB pcb = new PCB(
                );

        //将PCB插入到就绪队列中
        ListNode listNode = new ListNode();

        readyList.insertIntoListFirst(listNode);

        pcb.setListNode(listNode);

        //TODO: 尚未写完，分配资源

        return StatusCode.SUCCEED;
    }

    /**
     * 撤销进程API
     */
    public boolean destroy(int pid) {

        //TODO: 尚未写完，取消PCB，释放资源等

        return true;
    }

    /**
     * 递归撤销所有子孙进程API
     */
    public boolean killTree(int pid) {

        return true;
    }

    /**
     * 请求资源API
     */
    public void request() {

    }

    /**
     * 释放资源API
     */
    public void release() {

    }

    /**
     * 时钟中断API
     */
    private void timeOut() {
        //System.out.println("时钟中断(" + clockInterruptNo + ")");
        clockInterruptNo++;


        //TODO: 调度方法都在这里
    }

    /**
     * 系统中断API
     */
    public void interrupt(int type) {

        //TODO 来自用户的中断（例如键盘输入操作）

    }

    /**
     * 给名字找线程号
     */
    public int[] findProcess(String processName) {


        return new int[0];
    }

    /**
     * 给PID找进程
     * */
    public TreeNode findParentProcessTreeNode(int parentPID) {

        return null;
    }

}
